﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BidFunLib.BidWeb.Sale;
using BidFunLib.Services;
using log4net;
using System.Windows.Forms;
using BidFunLib.Entity;

namespace BidFunLib.BidWeb
{
    /// <summary>
    /// Parse the first page ( www.bidfun.fr )
    /// Launch Bid Sale Logger using the Automatic bid list
    /// </summary>
    public abstract class BidWebRootEngine<T> where T : BidWebSaleEngine
    {
        #region Members

        public static readonly ILog Log = LogManager.GetLogger(typeof(BidWebRootEngine<T>));
        /// <summary>
        /// URL : www.bidfun.fr
        /// </summary>
        public String Url { get; set; }
        /// <summary>
        /// Main Web Browser
        /// </summary>
        public WebBrowser Browser { get; set; }
        /// <summary>
        /// Robot for login
        /// </summary>
        public BidWebLogin LoginWeb { get; set; }
        /// <summary>
        /// Data Base login
        /// </summary>
        BidLogin myLogin = new BidLogin();

        public List<StatsBidSale> StatsList { get; set; }
        /// <summary>
        /// Selected BidSale For Spy
        /// </summary>
        public List<BidObjectSpy> SelectedBidObjectForSpy { get; set; }
        /// <summary>
        /// True : Store and Start only BidSale in SelectedBidSaleForSpy
        /// False : Store all BidSale but start only bid in SelectedBidSaleForSpy
        /// </summary>
        public Boolean AllSales { get; set; }

        public BidSaleWebEngineManager<T> SaleWebManager { get; set; }

        private Timer ReParseTimer = new Timer();

        #endregion

        #region event

        public event OnLoginEventHandler Onlogin;
        public event OnBidListUpdateEventHandler OnBidListUpdate;

        #endregion

        public BidWebRootEngine()
        {
            AllSales = false;
            StatsList = new List<StatsBidSale>();

            Log.Info("BidWebLogger");
            Url = "www.bidfun.fr";
            LoginWeb = new BidWebLogin(new BidLogin("", ""), false);
            SelectedBidObjectForSpy = new List<BidObjectSpy>();
            Browser = new WebBrowser();
            Browser.Visible = false;

            ReParseTimer.Interval = 1000 * 120; // 2 Minutes

            ReParseTimer.Tick += new EventHandler(ReParseTimer_Tick);
        }


        /// <summary>
        /// New Sale Detected
        /// </summary>
        /// <param name="bid_url"></param>
        /// <param name="objectLabel"></param>
        /// <param name="robot"></param>
        /// <param name="beginnerOnly"></param>
        /// <param name="bidNumber"></param>
        public abstract void newSaleDetected(string bid_url ,string objectLabel, bool robot, bool beginnerOnly,int bidNumber);
        /// <summary>
        /// Called when main site have been parsed
        /// </summary>
        public abstract void postBidParsing();

        /// <summary>
        /// Initialise the Browser
        /// </summary>
        public void Start()
        {
            if (Browser != null)
            {
                Browser.DocumentCompleted -= Browser_DocumentCompleted;
            }
            else
            {
                Browser = new WebBrowser();
            }
            Log.Info("BidWebLogger : Start");
            Browser.Navigate(Url);

            if (LoginWeb == null)
            {
                throw new Exception("BidWebLogger Init Login");
            }
            Browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(Browser_DocumentCompleted);
            Browser.Navigate(Url);
        }



        public void Browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            Log.Info("BidWebSniffer : Browser_DocumentCompleted " + Browser.Url.Host);

            if (Browser.Url.Host == Url)
            {

                if (LoginWeb.EnableLogin == true) // Login obligatoire
                {
                    if (LoginWeb.isLoged(Browser.Document) == true)
                    {
                        UpdateBidSaleList(true);
                        if (Onlogin != null)
                        {
                            Onlogin();
                        }
                        return;
                    }

                    if (LoginWeb.CheckForLogin(Browser.Document)) // Demande de connexion
                    {
                        LoginWeb.DoLogin(Browser.Document); // Do Login and clean SaleManager
                        SaleWebManager.Map.Clear();
                        return;
                    }
                }
                else 
                {
                    if (LoginWeb.isLoged(Browser.Document) == true) // Demande de deco
                    {
                        LoginWeb.logOut(Browser.Document); // Do logout and clean SaleManager
                        SaleWebManager.Map.Clear();
                    }
                    else
                    {
                        UpdateBidSaleList(false);
                        if (Onlogin != null)
                        {
                            Onlogin();
                        }
                        return;
                    }
                }
            }
        }

        /// <summary>
        /// Parse the Html Document and launch BidWebLogger if needed
        /// </summary>
        public void UpdateBidSaleList(Boolean isLoged)
        {
            Log.Info("BidWebSniffer : UpdateBidSaleList :  ListAuto " + SelectedBidObjectForSpy.Count);

            HtmlDocument doc = Browser.Document;
            HtmlElement elm = null;
            String bid_url = "";
            String objectLabel = "";

            int i = 14;

            if (isLoged == true)
            {
                i = 14; // Si login
            }
            else
            {
                i = 12; // mode logger
            }
            int j = 0;
            for (; i < Browser.Document.Links.Count - 4; i += 4)
            {
                if (i > Browser.Document.Links.Count - 4)
                {
                    break;
                }
                elm = doc.Links[i];
                if (elm != null)
                {
                    bool robot = false;
                    if (doc.Links[i + 1].OuterText != null)
                    {
                        if (doc.Links[i + 1].OuterText.ToLower().Contains("robot"))
                        {
                            robot = true;
                        }
                    }
                    bool beginnerOnly = false;
                    if (elm.Parent != null && elm.Parent.InnerHtml != null)
                    {
                        if (elm.Parent.InnerHtml.Contains("Débutants uniquement"))
                        {
                            beginnerOnly = true;
                        }
                    }
                    bid_url = elm.GetAttribute("HREF");                  
                    objectLabel = elm.OuterText;

                    Console.WriteLine(">> Bid Object : " + objectLabel + "URL " + bid_url + " <<");

                    newSaleDetected(bid_url, objectLabel, robot, beginnerOnly,j++);
                }
            }

            if (OnBidListUpdate != null)
            {
                OnBidListUpdate();
            }         
            postBidParsing();
        }


        public void newBid_StatsHander(StatsBidSale stats)
        {
            StatsList.Add(stats);
        }

        /// <summary>
        /// Bid Sale Ended
        /// </summary>
        public void SaleManager_bidEndedEvent(BidWebSaleEngine sale)
        {
            Log.Info("Bid Sale Ended Post TimerBidEnded for [ " + sale.Sale.BidFunIdentifier + " ]");
            SaleWebManager.Map.Remove(sale.Url);
            ReParseTimer.Start();
        }


        void ReParseTimer_Tick(object sender, EventArgs e)
        {
            Log.Info("TimerBidEnded Tick : looking for new Bid Sale");
            Browser = new WebBrowser();
            Browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(Browser_DocumentCompleted);
            Browser.Navigate(Url);
            ReParseTimer.Stop();
        }

    }

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class BidSaleWebEngineManager<T> where T : BidWebSaleEngine
    {
        public Dictionary<String, T> Map { get; set; }

        public BidSaleWebEngineManager()
        {
            Map = new Dictionary<string, T>();
        }

        /// <summary>
        /// Get BidSaleWeb object by URL
        /// URL is the KEY
        /// </summary>
        /// <param name="url"></param>
        /// <param name="web"></param>
        /// <returns></returns>
        public BidWebSaleEngine getBySaleURL(String url)
        {
            T web;
            if (Map.ContainsKey(url))
            {
                Map.TryGetValue(url, out web);

            }
            else
            {
                web = createBid(url);
                Map.Add(url, web);
            }
            return web;
        }

        protected abstract T createBid(String url);


        public BidWebSaleEngine createBidSaleWeb(string bid_url, string objectLabel, bool robot, bool beginnerOnly)
        {
            T newBid = createBid(bid_url);
            Map.Add(bid_url, newBid);
            newBid.Sale.BidObject = BidObjectManager.Instance.getObjectByLabel((objectLabel));
            newBid.Sale.Label = newBid.Sale.BidObject.Label;
            newBid.Sale.BidFunBotAuthorized = robot;
            newBid.Sale.BeginnerOnly = beginnerOnly;
            return newBid;
        }

        public bool CheckForSale(String URL)
        {
            return Map.ContainsKey(URL);
        }

        /// <summary>
        /// Start all bids in maps
        /// </summary>
        public void StartBids()
        {
            foreach (T item in Map.Values)
            {
                item.Start();
            }
        }

        public void StartBid(String url)
        {
            T val;
            Map.TryGetValue(url,out val);
            if (val != null)
            {
                val.Start();
            }
        }
    }
}
